#include "BSpline.h"

/********************************************************************************************************
Constructor & Destructor
********************************************************************************************************/

//Default Constructor
BSpline::BSpline(){
}


//Constructor with degree & resolution, compute all passage points
BSpline::BSpline(float* vertex, int nbPoints, int degree, int resolution){

	m_lineClose = isLineClose(vertex, nbPoints);

	computePassagePoints(vertex, nbPoints, degree, resolution);
	m_nbPoints = resolution -1;
}


BSpline::~BSpline(){
}





/********************************************************************************************************
Compute BSpline Curve
********************************************************************************************************/

void BSpline::computePassagePoints(float* vertex, int nbPoints, int degree, const int resolution){
    float *result = new float[resolution * 3];
	
    int *intervals = computeIntervals(nbPoints - 1, degree);

    float step = (float)((nbPoints - 1 - degree + 2) / (float)(resolution - 1));

    float current = 0;
	float* temp;

	
    for (int i = 0; i < resolution * 3 ; i++)
    {
		temp = bSplineValue(intervals, nbPoints, degree, current, vertex);
		result[i++] = temp[0];
		result[i++] = temp[1];
		result[i] = temp[2];

		//std::cout<<temp[0]<<std::endl;
      
      current += step;
    }
	
	result[resolution * 3 -3] = vertex[nbPoints - 3];
	result[resolution * 3 -2] = vertex[nbPoints - 2];
	result[resolution * 3 -1] = vertex[nbPoints - 1];

	

    m_vertex = result;
}

int* BSpline::computeIntervals(int nbPoints, int degree)
{	
  int *intervale = new int[nbPoints + degree + 1];
  
  for (int i = 0; i < nbPoints + degree; i++)
  {
    if (i < degree)
      intervale[i] = 0;
    else
    {
      if (degree <= i && i <= nbPoints)
        intervale[i] = i - degree + 1;
      else if (i > nbPoints)
        intervale[i] = nbPoints - degree + 2;
    }
  }
  
  return intervale;  
}


float* BSpline::bSplineValue(int* intervals, int nbPoints, int degree, float value, float* vertex)
{
	float* result = new float[3];
	result[0] = 0;
	result[1] = 0;
	result[2] = 0;
	
  //Vector3 result = new Vector3(0, 0, 0);

  for (int i = 0; i < nbPoints; i++)
  {
    float compute = computePoint(i, degree, intervals, value);
      
    //result = result + arrayPos[i].position * compute;
	result[0] = result[0] + vertex[(i * 3)] * compute;
	result[1] = result[1] + vertex[(i * 3) + 1] * compute;
	result[2] = result[2] + vertex[(i * 3) + 2] * compute;
  }    

  return result;
}

float BSpline::computePoint(int step, int degree, int* intervals, float value){
    float result = 0;
    
    if (degree == 1)
    {
      
      if (intervals[step] <= value && value < intervals[step + 1])
        result =  1;
      else
        result = 0;
    }

    else
    {
      if (intervals[step + degree - 1] == intervals[step] && intervals[step + degree] == intervals[step + 1])
        result = 0;
      else if (intervals[step + degree - 1] == intervals[step])
        result = (intervals[step + degree] - value) / (intervals[step + degree] - intervals[step + 1]) * computePoint(step + 1, degree - 1, intervals, value);
      else if (intervals[step + degree] == intervals[step + 1])
        result = (value - intervals[step]) / (intervals[step + degree - 1] - intervals[step]) * computePoint(step, degree - 1, intervals, value);
      else
      {
        result = (value - intervals[step]) / (intervals[step + degree - 1] - intervals[step]) * computePoint(step, degree - 1, intervals, value) + (intervals[step + degree] - value) / (intervals[step + degree] - intervals[step + 1]) * computePoint(step + 1, degree - 1, intervals, value);
      }
    
    }


    return result;
}
	



